#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sysinfo.h>

#include "MainProc.h"
#include "SvrMgr.h"
#include "Server.h"
#include "ModMgr.h"

CMainProc::CMainProc()
{
    m_nCore = 0;
    m_bMainSvr = 0;
    m_pSvr = nullptr;
    m_pSvrMgr = nullptr;
    m_pModMgr = nullptr;
}

CMainProc::~CMainProc()
{
    Destroy();
}

bool CMainProc::Init()
{
    m_nCore = get_nprocs();
    // 需放在最前面，创建CSvrMemBlock并创建CSvrMgr
    m_pSvrMgr = CSvrMgr::Create(m_nCore);

    if (nullptr == m_pSvrMgr)
        return false;

    if (!m_pSvrMgr->Init())
        goto FailedLabel;

    m_pModMgr = CModMgr::GetInstance();

    if (nullptr == m_pModMgr)
        goto FailedLabel;

    if (!m_pModMgr->Init())
        goto FailedLabel;

    return true;

FailedLabel:
    Destroy();
    return false;
}

bool CMainProc::Start()
{
    pid_t pid = -1;
    int *fds = nullptr;
    CServer *pSvr = nullptr;
    int *pfds = (int *)malloc((m_nCore + 1) * 2 * sizeof(int));

    if (nullptr == pfds)
        return false;

    fds = pfds;

    for (size_t iLoop = 0; iLoop <= m_nCore; iLoop++)
    {
        if (-1 == socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
        {
            // 待做：出错close之前的fds
            free(pfds);
            return false;
        }

        fds += 2;
    }

    fds = pfds;

    if (!CreateMainSvr(&m_pSvr))
        return false;

    for (size_t indx = 0; indx < m_nCore; indx++)
    {
        // 主进程中创建CWorkSvr实例
        if (!CreateWorkSvr(&pSvr))
            return false;

        pid = fork();

        if (0 == pid)
        {
            int iRet = -1;
            cpu_set_t csMask;

            // 绑定进程到CPU
            CPU_ZERO(&csMask);
            CPU_SET((int)indx, &csMask);
            iRet = sched_setaffinity(0, sizeof(csMask), &csMask);

            if (-1 == iRet)
                printf("Set CPU affinity failed.\n");

            break;
        }

        fds += 2;
    }

    if (0 == pid)
    {
        m_pSvr = pSvr;
        m_bMainSvr = false;

        m_pSvr->Init(fds);

        free(pfds);
        m_pSvr->Start();
    }
    else if (0 < pid)
    {
        m_bMainSvr = true;
        m_pSvr->Init(fds);
        free(pfds);
        m_pSvr->Start();
    }
    else
    {
        printf("Error: fork error!\n");
        return false;
    }

    return true;
}

bool CMainProc::Stop()
{
    if (nullptr != m_pSvr)
    {
        m_pSvr->Stop();
    }

    return true;
}

void CMainProc::Destroy()
{
    if (m_bMainSvr)
    {
        pid_t pid;
        int iStatus;

        while (0 < (pid = wait(&iStatus)))
            ;

        if ((nullptr != m_pSvr) && (nullptr != m_pSvrMgr))
        {
            m_pSvrMgr->DestroyMainSvr((CMainSvr *)m_pSvr);
            m_pSvr = nullptr;
        }

        if (nullptr != m_pModMgr)
        {
            m_pModMgr->Destroy();
            delete m_pModMgr;
            m_pModMgr = nullptr;
        }

        if (nullptr != m_pSvrMgr)
        {
            delete m_pSvrMgr;
            m_pSvrMgr = nullptr;
        }
    }
    else
    {
        if ((nullptr != m_pSvr) && (nullptr != m_pSvrMgr))
        {
            m_pSvrMgr->DestroyWorkSvr((CWorkSvr *)m_pSvr);
            m_pSvr = nullptr;
        }

        if (nullptr != m_pModMgr)
        {
            m_pModMgr->Destroy();
            delete m_pModMgr;
            m_pModMgr = nullptr;
        }
    }
}

bool CMainProc::CreateMainSvr(CServer **pSvr)
{
    *pSvr = (CServer *)m_pSvrMgr->CreateMainSvr();

    if (nullptr == pSvr)
    {
        kill(0, SIGINT);
        return false;
    }

    return true;
}

bool CMainProc::CreateWorkSvr(CServer **pSvr)
{
    *pSvr = (CServer *)m_pSvrMgr->CreateWorkSvr();

    if (nullptr == pSvr)
    {
        kill(0, SIGINT);
        return false;
    }

    return true;
}